package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

func main() {
	/*
		1.切片名 作为函数参数和指针传递时一样的效果

		2.nil切片 和 空切片：
			make([]int, 0) 创建的切片，内部指针有分配，为 空切片
			var a []int 创建的切片，内部指针为0，为 nil 切片

		3.多切片共享一个底层数组，其中一个切片的 append 操作可能会引发如下两种情况：
		（1）append 追加的元素没有超过底层数组的容量：
			此时，append操作会直接操作共享的底层数组，如果其他切片有引用数组被覆盖的元素，则会导致其他切片的值也隐式地发生变化
		（2）append 追加的元素加上原来的元素如果超过了底层数组的容量：
			此时，append操作会重新申请数组，并将原来的数组值复制到新数组

		注：由于这种二义性，所以使用切片的过程中应该尽量避免多个切片共享底层数组，可以使用 copy 进行显示的复制
	*/
	a := []int{0, 1, 2, 3, 4, 5, 6}
	b := a[0:4]

	//使用反射中的 SliceHeader 来获取切片运行时的数据结构
	as := (*reflect.SliceHeader)(unsafe.Pointer(&a))
	bs := (*reflect.SliceHeader)(unsafe.Pointer(&b))

	//a、b 共享底层数组
	fmt.Printf("a=%v,len=%d,cap=%d,type=%d\n", a, len(a), cap(a), as.Data) //a=[0 1 2 3 4 5 6],len=7,cap=7,type=824633795392
	fmt.Printf("b=%v,len=%d,cap=%d,type=%d\n", b, len(b), cap(b), bs.Data) //b=[0 1 2 3],len=4,cap=7,type=824633795392

	b = append(b, 10, 11, 12)

	//a、b 继续共享底层数组，修改 b 会影响共享的底层数组，间接影响 a
	fmt.Printf("a=%v,len=%d,cap=%d\n", a, len(a), cap(a)) //a=[0 1 2 3 10 11 12],len=7,cap=7
	fmt.Printf("b=%v,len=%d,cap=%d\n", b, len(b), cap(b)) //b=[0 1 2 3 10 11 12],len=7,cap=7

	//len(b)=7，底层数组容量是7，此时需要重新分配数组，并将原数组的值复制到新数组
	b = append(b, 13, 14)

	as = (*reflect.SliceHeader)(unsafe.Pointer(&a))
	bs = (*reflect.SliceHeader)(unsafe.Pointer(&b))

	//可以看到 a 和 b 指向的底层数组指针已经不同了，a 仍然指向原来的数组，但是 b 指向了一个新的数组
	fmt.Printf("a=%v,len=%d,cap=%d,type=%d\n", a, len(a), cap(a), as.Data) //a=[0 1 2 3 10 11 12],len=7,cap=7,type=824633795392
	fmt.Printf("b=%v,len=%d,cap=%d,type=%d\n", b, len(b), cap(b), bs.Data) //b=[0 1 2 3 10 11 12 13 14],len=9,cap=14,type=824633843936
}
